dojo.provide("dojoscratch.Board");
dojo.require("dojox.gfx");
dojo.require("dojoscratch.Scratch");
dojo.require("dojoscratch.TextScratch");

dojo.declare("dojoscratch.Board", null, {
	
	constructor: function(containerId, data) {
		this._id = data.id;
		this._boardWidth = data.uiData.boardData.width;
		this._boardHeight = data.uiData.boardData.height;
		this._boardChannel = "/scratchcrew/board/" + this._id;
		this._boardNode = dojo.byId(containerId);
		this._surface  = dojox.gfx.createSurface(this._boardNode,
				this._boardWidth, this._boardHeight);
		this._scratchTransformSubscribtion = 
			dojo.subscribe("scratchTransform", this, "_onScratchTransform");
		this._textTransformSubscribtion = 
			dojo.subscribe("textTransform", this, "_onTextTransform");
		this._scratchCreateSubscribtion = 
			dojo.subscribe("scratchCreate", this, "scratch");
		this._changeActiveCommandSubscribtion = 
			dojo.subscribe("changeActiveCommand", this, "_setActiveCommand");
		this._activatedSubscribtion = 
			dojo.subscribe("activated", this, "_setActiveScratch");
		//TODO connect to DEL button (for active scratch)
		
		// XXX this should be extended to handle other cases:
		this._changeScaleModeSubscribtion = 
			dojo.subscribe("changeScaleMode", this, "_setScaleMode");

		this._activeCommand = null;
		this._pointingSubscribtion = 
			dojo.subscribe("pointing", this, "_pointing");
		this._pointGroup = this._surface.createGroup();
		
		var domNode = this._surface.getEventSource();
		dojo.connect(domNode, "onmousedown", this, "_onmousedown");
		dojo.connect(domNode, "onmousemove", this, "_onmousemove");
		dojo.connect(domNode, "onmouseup", this, "_onmouseup");
		this._scratches = [];
		var initScratches =  data.uiData.scratches;

		for(i = 0; i < initScratches.length; i++) {
			this.createShape(initScratches[i]);
		}

	},
	_setScaleMode: function(enable) {
		dojo.forEach(this._scratches, 
			    function(oneEntry, index, array) {
					if(oneEntry) {
						oneEntry.setScalable(enable);
					}
			    }
		);
	},
	_setActiveScratch: function(activeScratch) {
		if (this._activeScratch == activeScratch) {
			//no changes
			return;
		}

		if (this._activeScratch && this._activeScratch.onDeactivation) {
			//deactivate previous active scratch
			this._activeScratch.onDeactivation();
		}

		this._activeScratch = activeScratch;
		
		//activate new scratch
		if (this._activeScratch && this._activeScratch.onActivation) {
			this._activeScratch.onActivation();
		}
	},
	_setActiveCommand: function(activeCommand) {
		//enable or disable "move"
		if (null == activeCommand) {
			this._boardNode.style.cursor = 'default';
		} else {
			this._boardNode.style.cursor = 'crosshair';
		}
		dojo.forEach(this._scratches, 
			    function(oneEntry, index, array) {
					if(oneEntry) {
						oneEntry.setMovable(null == activeCommand);
					}
			    }
		);

		this._activeCommand = activeCommand;
	},
	getId: function() {
		return this._id;
	},
	_onmousedown: function(event) {
		if (this._activeCommand) {
			var x = event.pageX;
			var y = event.pageY;
			this._activeCommand.start(x, y);
		}
		event.preventDefault();
	},
	_onmousemove: function(event) {
		if (this._activeCommand) {
			var x = event.pageX;
			var y = event.pageY;
			this._activeCommand.doing(x, y);
		}
		event.preventDefault();
	},
	_onmouseup: function(event) {
		if (this._activeCommand) {
			var x = event.pageX;
			var y = event.pageY;
			this._activeCommand.end(x, y);
		}
		event.preventDefault();
	},
	_onScratchTransform: function(scratchId, scratchMatrix) {
		if (!scratchId) {
			return false;
		}
		dojox.cometd.publish(this._boardChannel, {
			"type" : "transformScratch",
			"transform" : scratchMatrix,
			"id" : scratchId
		});
	},
	_onTextTransform: function(scratchId, shape, font) {
		if (!scratchId) {
			return false;
		}
		dojox.cometd.publish(this._boardChannel, {
			"type" : "transformText",
			"id" : scratchId,
			"staticData": {
				"shape" : shape
				},
			"scratchData": {
					"font" : font
			}
		});
	},
	transformScratch: function(data) {
		console.debug(data);
		console.debug(this._scratches);
		console.debug(this._scratches[data.id]);
		this._scratches[data.id].transform(data.transform);
	},
	transformText: function(data) {
		this._scratches[data.id].setSettings(data.staticData.shape,
				data.scratchData.font);
	},
	_pointing : function(shape, fill,stroke) {
		if (!shape) {
			return false;
		}
		console.debug("sending pointing message");
		console.debug(shape);
		dojox.cometd.publish(this._boardChannel,{
			"type": "pointing",
			"content" : {
				"staticData" : {
					"shape" : shape
				},
				"scratchData": {
					"fill" 	: fill,
					"stroke": stroke
				}
			}
		});
	},
	scratch : function(shape, fill, stroke) {
		if (!shape) {
			return false;
		}
		dojox.cometd.publish(this._boardChannel, {
			"type" 	: "createScratch",
			"content": {
				"staticData": {"shape" : shape},
				"scratchData" : {
					"fill" 	: fill,
					"stroke": stroke
				}
			}
		});
	},
	createShape: function(data) {
		console.debug("creating shape");
		console.debug(data);
		if("text" == data.staticData.shape.type) {
			//TODO how to avoid handling exclusions in that way?!
			this._scratches[data.id] =  new dojoscratch.TextScratch(this._surface,
					data.id, data.staticData.shape, data.scratchData.fill, data.scratchData.stroke);
		} else {
			this._scratches[data.id] = new dojoscratch.Scratch(this._surface,
					data.id, data.staticData.shape, data.scratchData.fill, data.scratchData.stroke, data.scratchData.matrix);
		}
	},
	createImageShape: function(imageSrc) {
		//based on org.scratchcrew.web.upload.UploadHandler#doHandleRequest()
		dojox.cometd.publish(this._boardChannel, {
			"type": "createScratch",
			"content": {
				"staticData": {
					"shape": {
						"type": "image",
						"x": 0,
						"y": 0,
						"width": 450,
						"height": 200,
						"src": imageSrc
					}
				}
			}
		});	
	},
	sendRemoveActiveScratch: function() {
		if (!this._activeScratch) {
			console.debug("no active scratch to remove");
			return;
		}
		dojox.cometd.publish(this._boardChannel, {
			"type" 	: "removeScratch",
			//TODO how to get scratch id from scratch?
			"scratchId": this._activeScratch._scratchId 
		});		
	},
	removeScratch: function(scratchId) {
		console.debug("removeScratch");
		var scratch = this._scratches[scratchId];
		if (scratch) {
			console.debug("removing scratch:");
			console.debug(scratch);
			scratch.remove();
		}
	},
	//by convention 0 - send to back, -1 - bring to front
	sendChangeZIndexOfActiveScratch: function(zIndex) {
		if (!this._activeScratch) {
			console.debug("no active scratch to change Z index");
			return;
		}
		dojox.cometd.publish(this._boardChannel, {
			"type" 	: "changeZIndex",
			//TODO how to get scratch id from scratch?
			"scratchId": this._activeScratch._scratchId,
			"zIndex": zIndex
		});		
	},
	changeZIndex: function(scratchId, zIndex) {
		console.debug("sendChangeZIndex: "+zIndex);
		var scratch = this._scratches[scratchId];
		if (scratch) {
			console.debug("changing index for scratch:");
			console.debug(scratch);
			scratch.changeZIndex(zIndex);
		}
	},
	drawPointing : function(data) {
		console.debug("drawing pointing ...");
		console.debug(data);
	    var shape = this._pointGroup.createShape(data.staticData.shape);
	    shape.setFill(data.scratchData.fill.colors.color);
	    setTimeout(function(){
	    	shape.removeShape(true);
	    }, 3000);
	}
});